package com.fox.stock.utils;

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;

import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author by itheima
 * @Date 2021/12/31
 * @Description 日期时间工具类
 */
public class DateTimeUtil {

    /**
     * 获取指定日期下股票的上一个有效交易日时间
     * @return
     */
    public static DateTime getPreviousTradingDay(DateTime dateTime){
        //获取指定日期对应的工作日
        int weekNum = dateTime.dayOfWeek().get();
        //判断所属工作日
        DateTime preDateTime=null;
        //周一，那么T-1就是周五
        if (weekNum==1){
            //日期后退3天
          preDateTime=dateTime.minusDays(3);
        }
        //周末，那么T-1就是周五
        else if (weekNum==7){
            preDateTime=dateTime.minusDays(2);
        }
        else {
            preDateTime=dateTime.minusDays(1);
        }
        return getDateTimeWithoutSecond(preDateTime);
    }

    /**
     * 判断是否是工作日
     * @return true：在工作日 false:不在工作日
     */
    public static boolean isWorkDay(DateTime dateTime){
        //获取工作日
        int weekNum = dateTime.dayOfWeek().get();
        return  weekNum>=1 && weekNum<=5;
    }

    /**
     * 获取上一天日期
     * @param dateTime
     * @return
     */
    public static DateTime getPreDateTime(DateTime dateTime){
        return dateTime.minusDays(1);
    }

    /**
     * 日期转String
     * @param dateTime 日期
     * @param pattern 日期正则格式
     * @return
     */
    public static String parseToString(DateTime dateTime,String pattern){
       return  dateTime.toString(DateTimeFormat.forPattern(pattern));
    }

    /**
     * 获取股票日期格式字符串
     * @param dateTime
     * @return
     */
    public static String parseToString4Stock(DateTime dateTime){
        return parseToString(dateTime,"yyyyMMddHHmmss");
    }

    /**
     * 获取指定日期的收盘日期
     * @param dateTime
     * @return
     */
    public static DateTime getCloseDate(DateTime dateTime){
       return dateTime.withHourOfDay(15).withMinuteOfHour(1).withSecondOfMinute(0).withMillisOfSecond(0);
    }

    /**
     * 获取指定日期的开盘日期
     * @param dateTime
     * @return
     */
    public static DateTime getOpenDate(DateTime dateTime){
       return dateTime.withHourOfDay(9).withMinuteOfHour(31).withSecondOfMinute(0).withMillisOfSecond(0);
    }

    /**
     * 获取最近的股票有效时间，精确到分钟
     * @param target
     * @return
     */
    public static String getLastDateString4Stock(DateTime target){
        DateTime dateTime = getLastDate4Stock(target);
        dateTime=getDateTimeWithoutSecond(dateTime);
        return parseToString4Stock(dateTime);
    }
    /**
     * 获取最近的股票有效时间，精确到分钟
     * @param target
     * @return
     */
    public static DateTime getLastDate4Stock(DateTime target){
        //判断是否是工作日
        if (isWorkDay(target)) {
            //当前日期开盘前
            if (target.isBefore(getOpenDate(target))) {
                target=getCloseDate(getPreviousTradingDay(target));
            }else if (isMarketOffTime(target)){
                target=target.withHourOfDay(11).withMinuteOfHour(31).withSecondOfMinute(0).withMillisOfSecond(0);
            }else if (target.isAfter(getCloseDate(target))){
                //当前日期收盘后
                target=getCloseDate(target);
            }
        }else{
            //非工作日
            target=getCloseDate(getPreviousTradingDay(target));
        }
         target = getDateTimeWithoutSecond(target);
        return target;
    }

    /**
     * 判断当前时间是否在大盘的中午休盘时间段
     * @return
     */
    public static boolean isMarketOffTime(DateTime target){
        //上午休盘开始时间
        DateTime start = target.withHourOfDay(11).withMinuteOfHour(31).withSecondOfMinute(0).withMillisOfSecond(0);
        //下午开盘时间
        DateTime end = target.withHourOfDay(13).withMinuteOfHour(1).withSecondOfMinute(0).withMillisOfSecond(0);
        if (target.isAfter(start) && target.isBefore(end)) {
            return true;
        }
        return false;
    }

    /**
     * 将秒时归零
     * @param dateTime 指定日期
     * @return
     */
    public static DateTime getDateTimeWithoutSecond(DateTime dateTime){
        DateTime newDate = dateTime.withSecondOfMinute(0).withMillisOfSecond(0);
        return newDate;
    }

    /**
     * 将秒时归零
     * @param dateTime 指定日期字符串，格式必须是：yyyy-MM-dd HH:mm:ss
     * @return
     */
    public static DateTime getDateTimeWithoutSecond(String dateTime){
        DateTime parse = DateTime.parse(dateTime, DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
        return getDateTimeWithoutSecond(parse);
    }


    /**
     * 获取从周一到当前的所有收盘时间点
     * 对于已过收盘时间的日期，添加15:00作为收盘时间
     * 对于当天（未过收盘时间），添加当前时间
     * 周末则只计算到上周五的收盘时间
     *
     * @return 时间列表，按时间顺序排列
     */
    public static List<DateTime> getCloseDatesByWeek(DateTime now) {
        List<DateTime> list = new ArrayList<>();
        int week = now.getDayOfWeek();
        if (week == 1 && now.isBefore(DateTimeUtil.getOpenDate(now).minusMinutes(1))){
            for (int i = 3; i < 8; i++) {
                list.add(new DateTime(now.withMinuteOfHour(0).withSecondOfMinute(0).withHourOfDay(15).withMillisOfSecond(0).minusDays(i)));
            }

        } else if (week == 6) {
            for (int i = 1; i < 6; i++) {
                list.add(new DateTime(now.withMinuteOfHour(0).withSecondOfMinute(0).withHourOfDay(15).withMillisOfSecond(0).minusDays(i)));
            }
        } else if (week == 7) {
            for (int i = 2; i < 7; i++) {
                list.add(new DateTime(now.withMinuteOfHour(0).withSecondOfMinute(0).withHourOfDay(15).withMillisOfSecond(0).minusDays(i)));
            }
        } else {
            for (int i = 1; i < week; i++) {
                list.add(new DateTime(now.withMinuteOfHour(0).withSecondOfMinute(0).withHourOfDay(15).withMillisOfSecond(0).minusDays(i)));
            }
            if (now.isAfter(DateTimeUtil.getCloseDate(now).minusMinutes(1))){
                list.add(new DateTime(now.withMinuteOfHour(0).withSecondOfMinute(0).withHourOfDay(15).withMillisOfSecond(0)));
            }else if(now.isAfter(DateTimeUtil.getOpenDate(now).minusMinutes(1))) {
                list.add(DateTimeUtil.getLastDate4Stock(now).minusMinutes(1));
            }
        }
        return list;
    }

    // 获取这周周一的开盘时间
    public static DateTime getOpenDateByWeek1(DateTime now){
        if (now.isBefore(DateTimeUtil.getOpenDate(now).minusMinutes(1))){
            now = now.minusDays(1);
        }
        return now.withHourOfDay(9).withMinuteOfHour(30).withSecondOfMinute(0).withMillisOfSecond(0).minusDays(now.getDayOfWeek()-1);
    }

    // 获取周五的收盘时间(未到周五则返回当前最近交易时间) TODO: 实际上这一块时多余的,你只要调用获取最近交易时间和这个效果一样
    public static DateTime getCloseDateByWeek5(DateTime now){
        if (now.getDayOfWeek() == 5 && now.isAfter(getCloseDate(now).minusMinutes(1)) || now.getDayOfWeek() > 5){
            return now.withHourOfDay(15).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0).minusDays(now.getDayOfWeek() - 5);
        }else {
            return DateTimeUtil.getLastDate4Stock(now).minusMinutes(1);
        }
    }

    // 判断a时间是否在b时间之前
    public static boolean isBefore(DateTime a,DateTime b){
        Date date1 = a.toDate();
        Date date = b.toDate();
        return date1.before(date);
    }

}